import { App, Directive, DirectiveBinding } from "vue";

/**
 * Vue指令组件
 */
export default class DirectiveComponent {
    private static instance: DirectiveComponent = new DirectiveComponent();
    /**
     * Vue指令组件
     */
    public static get Default(): DirectiveComponent {
        return this.instance;
    }

    //#region drag

    private drag: Directive = {
        mounted: this.onDragMounted
    };

    private onDragMounted(element: HTMLElement, binding: DirectiveBinding) {
        function onMouseDown(downEvent: MouseEvent) {
            if (downEvent.button != 1) {
                return;
            }

            let elementLeft = downEvent.clientX - element.offsetLeft;
            let elementTop = downEvent.clientY - element.offsetTop;

            const downEventTarget = downEvent.target as HTMLElement;

            if (downEventTarget.hasAttribute('drag-trigger')) {
                function onMouseMove(moveEvent: MouseEvent) {
                    let left = moveEvent.clientX - elementLeft;
                    let top = moveEvent.clientY - elementTop;

                    let offsetWidth = 0;
                    let offsetHeight = 0;

                    if (binding.modifiers.offset) {
                        offsetWidth = element.clientWidth * 0.5;
                        offsetHeight = element.clientHeight * 0.5;
                    }

                    if (binding.modifiers.clamp) {
                        left = Math.min(Math.max(left, 0 + offsetWidth), window.innerWidth - element.offsetWidth + offsetWidth);
                        top = Math.min(Math.max(top, 0 + offsetHeight), window.innerHeight - element.offsetHeight + offsetHeight);
                    }

                    element.style.setProperty('left', `${left}px`);
                    element.style.setProperty('top', `${top}px`);
                    element.style.setProperty('right', `initial`);
                    element.style.setProperty('bottom', `initial`);
                }

                function onMouseUp(upEvent: MouseEvent) {
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);
                }

                document.addEventListener('mousemove', onMouseMove);

                document.addEventListener('mouseup', onMouseUp);
            }
        }

        element.addEventListener('mousedown', onMouseDown);
    }

    //#endregion

    //#region wheel

    private wheel: Directive = {
        mounted: this.onWheelMounted
    };

    private onWheelMounted(element: HTMLElement, binding: DirectiveBinding) {
        function onWheel(wheelEvent: WheelEvent) {
            element.scrollLeft += wheelEvent.deltaY;
        }

        element.addEventListener('wheel', onWheel);
    }

    //#endregion

    public Register(app: App<Element>): void {
        app.directive('drag', this.drag);
        app.directive('wheel', this.wheel);
    }
}